Borland Online And The Cobb Group Present:


May, 1995 - Vol. 2 No. 5

Advanced C++ programming - Reconstructing objects

When your programs create individual objects, you can use different constructors to build those objects with specific values. Typically, you'll provide multiple constructors for a class when you need to create the same type of object from more than one set of parameters.

However, when you create an array of objects, you must use the default constructor for each of the objects in the array. You can't initialize any of the array objects by using nondefault constructor values.

One solution to this problem would be to create an Init( ) function for setting the initial data member values. However, you wouldn't be able to initialize any data members that you've declared const (constant values for the object). In addition, this design forces you to call this Init( ) function either explicitly following the constructor or from inside a constructor, which makes building an object a two-step process.

Instead, you can provide your own version of operator new( ) that will rebuild an object at a specific location. In this arti-cle, we'll show how you can define this type of operator new( ) that you call using placement syntax.

Operator overload

In C++, unlike most other high-level programming languages, you can provide custom versions of many of the basic operators (operators belong to a special class of language elements that initiate some action when you apply them to a variable or expression). Providing your own version of a C++ operator is known as operator overloading. One of the operators you can overload is operator new( ), which controls how your program allocates memory for certain objects.

To create an object of a given class Wombat, you'll either create it in the current scope using the syntax

Wombat pete(4, 45);

or you'll create it dynamically using

Wombat* pete = new Wombat(4, 45);

(This creates the object in the application's global memory pool, known as the heap.)

Similarly, you can create an array of Wombat objects using either

Wombat wArray[10];

or

Wombat* wArray = new Wombat[10];

As these examples show, you can't specify constructor values for any of the objects, which forces you to provide a default con-structor for the Wombat class (a constructor that either has no arguments or default values for all arguments).

Unfortunately, you may not be able to provide a reasonable default constructor. Specifically, if you're creating an array of objects for a class that defines a const data member, you won't be able to alter that data member after you've constructed the object.

Likewise, if there are const data members, you won't be able to simply create a new object and copy its values into an array element using

wArray[2] = Wombat(3, 22);

This is because copy constructors and assignment operators can't modify the values of const data members.

However, you can define a version of operator new( ) that uses an existing ad-dress to construct an object. The function

void* operator new(size_t size, void* loc)
{ return loc; }

passes the address loc to the constructor. The constructor will then build the object at that location in the array.

Additionally, if you derive a new class from the Wombat class, you may be able to construct an object of that new class in place of a Wombat object in the array. (We'll cover this topic in more detail in the June issue.)

A rebuilding program

To see how you can use a placement syn-tax version of operator new( ), let's build a program that reconstructs an array object, in its current location. To begin, launch the Borland C++ Integrated Development Environment (IDE).

When the IDE's main window appears, choose New from the File menu. In the new editing window, enter the code from Listing A.


Listing A: RECTOR.CPP

#include 

struct Wombat
{
  const int data;
  Wombat(int Data = 0) :
    data(Data) {}
  void Data( )
  { cout << data << endl; }
};

void* operator new(size_t, void* loc)
{ return loc; }

int main( )
{
  Wombat wArray[3];

  // Call the placement syntax version
  // of operator new( )
  new(&wArray[1]) Wombat(5);

  wArray[0].Data( );
  wArray[1].Data( );
  wArray[2].Data( );

  return 0;
}

When you finish entering the code, choose Save As... from the File menu. In the File Name entry field of the Save File As dialog box, enter RECTOR.CPP and click OK.

Next, right-click on the editing window for the RECTOR.CPP file. Choose TargetExpert from the pop-up menu and then select EasyWin [.exe] from the Target Type list box of the Target Expert dialog box. Click OK to save this change.

Choose Run from the De-bug menu to build and run this application. When the EasyWin output window appears, you'll see the output

0
5
0

To understand what this program does, let's walk through the source code.

Reconstructing what happened

At the beginning of the main( ) function, you'll find the line

Wombat wArray[3];

This simple statement actually causes quite a bit of activity.

First, the program allocates enough space on the program stack for three Wombat objects. Then, the program calls the default constructor for each of these objects, pass-ing the addresses of the three array locations to the constructor. (Constructors always build objects at a specific location.)

The Wombat class doesn't define a normal default constructor (a constructor with no arguments), but it does define a constructor that has a default value for the only constructor argument. Since the program calls this constructor without specifying any arguments, it uses this constructor to build each of the array objects. After building the third object in the array, the program creates and in-itializes the array wArray, and it moves to the next line in the program.

Next, the program calls the placement syntax version of operator new( ) that ap-pears prior to the main( ) function. This version of operator new( ) doesn't allocate any memory. It simply returns (as a void*) the address that you pass to it­­in this case, the address of the second object in the array.

In C++, operator new( ) automatically passes its return value (the new object's address) to the constructor that follows. When the program calls the Wombat class's constructor with an argument of 5, the constructor rebuilds the Wombat object in the same memory location that used to contain a default Wombat object, as shown in Figure A.


Figure A - The placement syntax version of operator new( ) allows you to reconstruct an object in place.


Return to the Borland C++ Developer's Journal index

Subscribe to the Borland C++ Developer's Journal


Copyright (c) 1996 The Cobb Group, a division of Ziff-Davis Publishing Company. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis Publishing Company is prohibited. The Cobb Group and The Cobb Group logo are trademarks of Ziff-Davis Publishing Company.